#include <map>
#include <nice2d/metaobject.h>

class MetaObjectData
{
public:
    std::string name;
    const MetaObject* parent;
    uint32_t size;
    static const MetaObject* first;
    const MetaObject* next;
    static std::map<std::string,const MetaObject*> table;
};

const MetaObject* MetaObjectData::first = nullptr;
std::map<std::string,const MetaObject*> MetaObjectData::table;

MetaObject::MetaObject(const std::string &name,const MetaObject* parent,uint32_t size):
    data(new MetaObjectData)
{
    data->name = name;
    data->parent = parent;
    data->size = size;
    data->next = data->first;
    data->first = this;
}

MetaObject::~MetaObject()
{
    if(this == data->first)
    {
        data->first = data->next;
    }
    else
    {
        const MetaObject* info = data->first;
        while(info)
        {
            if(info->data->next == this)
            {
                info->data->next = data->next;
                break;
            }
            info = info->data->next;
        }
    }
}

std::string MetaObject::name()const
{
    return data->name;
}

uint32_t MetaObject::diskUsed()const
{
    return data->size;
}

bool MetaObject::isExactly(const MetaObject& type)const
{
    return &type == this;
}

bool MetaObject::isDerived(const MetaObject& type)const
{
    const MetaObject* search = this;
    while(search)
    {
        if(search == &type)
            return true;
        search = search->data->parent;
    }
    return false;
}

const MetaObject *MetaObject::first(){
    return MetaObjectData::first;
}

const MetaObject *MetaObject::next() const{
    return data->next;
}

const MetaObject *MetaObject::parent() const{
    return data->parent;
}

const MetaObject* MetaObject::metaObjectByObjectName(const std::string & objectname)
{
    if(MetaObjectData::table[objectname])
        return MetaObjectData::table[objectname];
    else
    {
        const MetaObject* info = MetaObjectData::first;
        for(;info; info = info->next())
        {
            if(info->name() == objectname)
            {
                MetaObjectData::table[objectname] = info;
                return info;
            }
        }
    }
    return nullptr;
}
